﻿Imports System.Net
Imports System.Text
Imports System.Web
Imports System.IO
Imports System.Runtime.Serialization
Imports Sgml
Imports System.Xml

Namespace Scraping
    Partial Class TwitterClient
        Implements ITwitterClient
        ''' <summary>
        ''' ステータスをポストした結果として返されるJSONを格納します。
        ''' </summary>
        ''' <remarks></remarks>
        <DataContract()> _
        Private Class UpdateStatusJsonResult
            Private _statusLi As String
            <DataMember(Name:="status_li")> _
            Public Property StatusListItem() As String
                Get
                    Return _statusLi
                End Get
                Set(ByVal value As String)
                    _statusLi = value
                End Set
            End Property

            Private _statusCount As Integer
            <DataMember(Name:="status_count")> _
            Public Property StatusCount() As Integer
                Get
                    Return _statusCount
                End Get
                Set(ByVal value As Integer)
                    _statusCount = value
                End Set
            End Property
        End Class

        ''' <summary>
        ''' ステータス文字列を指定して投稿します。
        ''' </summary>
        ''' <param name="status">ステータス文字列</param>
        ''' <returns>投稿されたステータス</returns>
        ''' <remarks></remarks>
        Public Function UpdateStatus(ByVal status As String) As TwitterStatus Implements ITwitterClient.UpdateStatus
            Return UpdateStatus(status, -1)
        End Function

        ''' <summary>
        ''' ステータス文字列と返信先のステータスを指定して投稿します。
        ''' </summary>
        ''' <param name="status">ステータス文字列</param>
        ''' <param name="inReplyToStatus">返信先のステータス</param>
        ''' <returns>投稿されたステータス</returns>
        ''' <remarks></remarks>
        Public Function UpdateStatus(ByVal status As String, ByVal inReplyToStatus As TwitterStatus) As TwitterStatus Implements ITwitterClient.UpdateStatus
            Return UpdateStatus(status, inReplyToStatus.StatusID)
        End Function

        ''' <summary>
        ''' ステータス文字列と返信先のステータスIDを指定して投稿します。
        ''' </summary>
        ''' <param name="status">ステータス文字列</param>
        ''' <param name="inReplyToStatusID">返信先のステータスID</param>
        ''' <returns>投稿されたステータス</returns>
        ''' <remarks></remarks>
        Public Function UpdateStatus(ByVal status As String, ByVal inReplyToStatusID As Long) As TwitterStatus Implements ITwitterClient.UpdateStatus
            If Not IsLogined Then
                Throw New InvalidOperationException(StrThisInstanceIsNotLoginedYet)
            End If

            Dim funcRet As TwitterStatus
            Dim url As String = String.Format("{0}{1}", My.Resources.TwitterUrl, My.Resources.TwitterUpdateStatusPath)
            Dim req As HttpWebRequest = DirectCast(WebRequest.Create(url), HttpWebRequest)
            req.SetTwitterXHRPostHeaders(My.Resources.TwitterUrl, _cookies)
            Dim sbPost As New StringBuilder()
            sbPost.AppendFormat("{0}={1}&", HttpUtility.UrlEncode(_authenticityTokenFiledName), HttpUtility.UrlEncode(_authenticityToken))
            sbPost.AppendFormat("{0}={1}&", "status", HttpUtility.UrlEncode(status, Encoding.UTF8))
            sbPost.AppendFormat("{0}={1}&", "twttr", "true")
            sbPost.AppendFormat("{0}={1}", "return_rendered_status", "true")
            If (inReplyToStatusID >= 0) Then
                sbPost.AppendFormat("&{0}={1}", "in_reply_to_status_id", inReplyToStatusID)
            End If
            Dim strPost As String = sbPost.ToString()
            req.PostString(strPost)
            Using res As HttpWebResponse = DirectCast(req.GetResponse(), HttpWebResponse)
                Select Case res.StatusCode
                    Case HttpStatusCode.OK
                        res.LoadCookies(_cookies)
                        Dim xmlRes As XmlDocument = Nothing
                        Using srRes As New StreamReader(res.GetResponseStream())
                            Dim jsonResult As UpdateStatusJsonResult = res.GetResponseAsJson(Of UpdateStatusJsonResult)()
                            If Not String.IsNullOrEmpty(jsonResult.StatusListItem) Then
                                xmlRes.LoadSgml(jsonResult.StatusListItem)
                            End If
                        End Using
                        If xmlRes IsNot Nothing Then
                            funcRet = ParseStatusListItem(xmlRes.DocumentElement, TimelineType.Home, Nothing)
                        Else
                            funcRet = Nothing
                        End If
                    Case Else
                        funcRet = Nothing
                End Select
            End Using
            Return funcRet
        End Function

        ''' <summary>
        ''' 投稿したステータスを削除します。
        ''' </summary>
        ''' <param name="statusID">ステータスID</param>
        ''' <returns>削除に成功すればTrue、失敗すればFalse</returns>
        ''' <remarks></remarks>
        Public Function DestroyStatus(ByVal statusID As Long) As Boolean Implements ITwitterClient.DestroyStatus
            If Not IsLogined Then
                Throw New InvalidOperationException(StrThisInstanceIsNotLoginedYet)
            End If

            Dim funcRet As Boolean
            Dim url As String = String.Format("{0}{1}{2}", My.Resources.TwitterUrl, My.Resources.TwitterDestroyStatusPath, statusID)
            Dim req As HttpWebRequest = DirectCast(WebRequest.Create(url), HttpWebRequest)
            req.SetTwitterXHRPostHeaders(My.Resources.TwitterUrl, _cookies)
            Dim sbPost As New StringBuilder()
            sbPost.AppendFormat("{0}={1}&", HttpUtility.UrlEncode(_authenticityTokenFiledName), HttpUtility.UrlEncode(_authenticityToken))
            sbPost.AppendFormat("{0}={1}", "latest_status", "false") 'TODO:最新かどうかの判別はできないか
            Dim strPost As String = sbPost.ToString()
            req.PostString(strPost)
            Using res As HttpWebResponse = DirectCast(req.GetResponse(), HttpWebResponse)
                Select Case res.StatusCode
                    Case HttpStatusCode.OK
                        funcRet = True
                    Case Else
                        funcRet = False
                End Select
            End Using
            Return funcRet
        End Function

        ''' <summary>
        ''' 指定したステータスをお気に入りに追加します。
        ''' </summary>
        ''' <param name="statusID">ステータスID</param>
        ''' <returns>追加に成功すればTrue、失敗すればFalse</returns>
        ''' <remarks></remarks>
        Public Function CreateFavorite(ByVal statusID As Long) As Boolean Implements ITwitterClient.CreateFavorite
            If Not IsLogined Then
                Throw New InvalidOperationException(StrThisInstanceIsNotLoginedYet)
            End If

            Dim funcRet As Boolean
            Dim url As String = String.Format("{0}{1}{2}", My.Resources.TwitterUrl, My.Resources.TwitterCreateFavoritePath, statusID)
            Dim req As HttpWebRequest = DirectCast(WebRequest.Create(url), HttpWebRequest)
            req.SetTwitterXHRPostHeaders(My.Resources.TwitterUrl, _cookies)
            Dim sbPost As New StringBuilder()
            sbPost.AppendFormat("{0}={1}", HttpUtility.UrlEncode(_authenticityTokenFiledName), HttpUtility.UrlEncode(_authenticityToken))
            Dim strPost As String = sbPost.ToString()
            req.PostString(strPost)
            Using res As HttpWebResponse = DirectCast(req.GetResponse(), HttpWebResponse)
                Select Case res.StatusCode
                    Case HttpStatusCode.OK
                        funcRet = True
                    Case Else
                        funcRet = False
                End Select
            End Using
            Return funcRet
        End Function

        ''' <summary>
        ''' 指定したステータスをお気に入りから削除します。
        ''' </summary>
        ''' <param name="statusID">ステータスID</param>
        ''' <returns>削除に成功すればTrue、失敗すればFalse</returns>
        ''' <remarks></remarks>
        Public Function DestroyFavorite(ByVal statusID As Long) As Boolean Implements ITwitterClient.DestroyFavorite
            If Not IsLogined Then
                Throw New InvalidOperationException(StrThisInstanceIsNotLoginedYet)
            End If

            Dim funcRet As Boolean
            Dim url As String = String.Format("{0}{1}{2}", My.Resources.TwitterUrl, My.Resources.TwitterDestroyFavoritePath, statusID)
            Dim req As HttpWebRequest = DirectCast(WebRequest.Create(url), HttpWebRequest)
            req.SetTwitterXHRPostHeaders(My.Resources.TwitterUrl, _cookies)
            Dim sbPost As New StringBuilder()
            sbPost.AppendFormat("{0}={1}", HttpUtility.UrlEncode(_authenticityTokenFiledName), HttpUtility.UrlEncode(_authenticityToken))
            Dim strPost As String = sbPost.ToString()
            req.PostString(strPost)
            Using res As HttpWebResponse = DirectCast(req.GetResponse(), HttpWebResponse)
                Select Case res.StatusCode
                    Case HttpStatusCode.OK
                        funcRet = True
                    Case Else
                        funcRet = False
                End Select
            End Using
            Return funcRet
        End Function
    End Class
End Namespace